package cn.stylefeng.guns.modular.household.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.core.exception.BusinessException;
import cn.stylefeng.guns.modular.household.entity.Household;
import cn.stylefeng.guns.modular.household.entity.HouseholdMember;
import cn.stylefeng.guns.modular.household.entity.HousingInfo;
import cn.stylefeng.guns.modular.household.exception.HouseholdEnum;
import cn.stylefeng.guns.modular.household.mapper.HouseholdMapper;
import cn.stylefeng.guns.modular.household.pojo.HouseholdAddRequest;
import cn.stylefeng.guns.modular.household.pojo.HouseholdMemberRequest;
import cn.stylefeng.guns.modular.household.pojo.HouseholdRequest;
import cn.stylefeng.guns.modular.household.pojo.HousingInfoRequest;
import cn.stylefeng.guns.modular.household.pojo.dto.HouseholdDto;
import cn.stylefeng.guns.modular.household.service.HouseholdMemberService;
import cn.stylefeng.guns.modular.household.service.HouseholdService;
import cn.stylefeng.guns.modular.household.service.HousingInfoService;
import cn.stylefeng.guns.modular.household.util.ValidatorUtils;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 户基本信息服务实现层
 *
 * @author lichenhui
 * @date 2024/03/20
 */
@Service
public class HouseholdServiceImpl extends ServiceImpl<HouseholdMapper, Household> implements HouseholdService {

    @Resource
    private HouseholdMemberService householdMemberService;

    @Resource
    private HousingInfoService housingInfoService;

    @Resource
    private HouseholdMapper householdMapper;

    /**
     * 分页查询权属户
     * @param request 查询参数
     * @return PageResult<Household>
     */
    @Override
    public PageResult<Household> findPage(HouseholdRequest request) {
        if (ObjectUtil.isNotEmpty(request.getHouseholdMemberName())) {
            request.setHouseholdMemberName("%" + request.getHouseholdMemberName() + "%");
        }
        Page<Household> reqPage = new Page<>(request.getPageNo(), request.getPageSize());
        LambdaQueryWrapper<Household> queryWrapper = createWrapper(request);
        Page<Household> resPage = householdMapper.findPage(reqPage, queryWrapper, request);

        return PageResultFactory.createPageResult(resPage);
    }

    /**
     * 添加权属户
     * @param request 请求参数
     */
    @Transactional
    @Override
    public void add(HouseholdAddRequest request) {
        if (ObjectUtil.isEmpty(request.getMembers())) {
            throw new BusinessException(HouseholdEnum.HOUSEHOLD_MEMBER_EMPTY_ERROR);
        }

        if (ObjectUtil.isEmpty(request.getHousingInfos())) {
            throw new BusinessException(HouseholdEnum.HOUSEHOLD_HOUSING_EMPTY_ERROR);
        }

        Household household = new Household();
        BeanUtil.copyProperties(request, household);
        household.setHouseholdId(IdUtil.getSnowflake().nextId());

        List<HouseholdMember> members = new ArrayList<>();
        // 家庭成员临时ID与实际ID映射
        Map<Long, Long> memberTmpIdMap = new HashMap<>();
        for (HouseholdMemberRequest memberRequest: request.getMembers()) {
            ValidatorUtils.validate(memberRequest, HouseholdMemberRequest.add.class);

            HouseholdMember member = new HouseholdMember();
            BeanUtil.copyProperties(memberRequest, member);
            member.setMemberId(IdUtil.getSnowflake().nextId());
            member.setHouseholdId(household.getHouseholdId());

            members.add(member);
            memberTmpIdMap.put(memberRequest.getMemberId(), member.getMemberId());
        }

        List<HousingInfo> housingInfos = new ArrayList<>();
        Double householdArea = 0d;
        for (HousingInfoRequest housingInfoRequest: request.getHousingInfos()) {
            ValidatorUtils.validate(housingInfoRequest, HousingInfoRequest.add.class);

            HousingInfo housingInfo = new HousingInfo();
            BeanUtil.copyProperties(housingInfoRequest, housingInfo);
            housingInfo.setHouseholdId(household.getHouseholdId());
            housingInfo.setHousingOwnerId(memberTmpIdMap.get(housingInfoRequest.getHousingOwnerId()));

            housingInfos.add(housingInfo);
            householdArea += housingInfo.getHousingArea();
        }

        household.setHouseholdSize(members.size());
        household.setHouseholdArea(householdArea);
        this.save(household);
        householdMemberService.saveBatch(members);
        housingInfoService.saveBatch(housingInfos);
    }

    /**
     * 删除权属户
     * @param request 请求参数
     */
    @Transactional
    @Override
    public void del(HouseholdRequest request) {
        Household household = this.getById(request.getHouseholdId());
        if (household == null) {
            throw new BusinessException(HouseholdEnum.HOUSEHOLD_NOT_FOUND);
        }

        // 软删除
        household.setDelFlag(YesOrNotEnum.Y.getCode());
        this.updateById(household);

        // 软删除关联的家庭成员
        List<HouseholdMember> members = householdMemberService.listByHouseholdId(household.getHouseholdId());
        members.forEach(member -> {
            member.setDelFlag(YesOrNotEnum.Y.getCode());
        });
        householdMemberService.updateBatchById(members);

        // 软删除关联的房屋信息
        List<HousingInfo> housingInfos = housingInfoService.listByHouseholdId(household.getHouseholdId());
        housingInfos.forEach(housingInfo -> {
            housingInfo.setDelFlag(YesOrNotEnum.Y.getCode());
        });
        housingInfoService.updateBatchById(housingInfos);
    }

    /**
     * 更新权属户
     * @param request 请求参数
     */
    @Transactional
    @Override
    public void edit(HouseholdAddRequest request) {
        if (ObjectUtil.isEmpty(request.getMembers())) {
            throw new BusinessException(HouseholdEnum.HOUSEHOLD_MEMBER_EMPTY_ERROR);
        }

        if (ObjectUtil.isEmpty(request.getHousingInfos())) {
            throw new BusinessException(HouseholdEnum.HOUSEHOLD_HOUSING_EMPTY_ERROR);
        }

        Household household = this.getById(request.getHouseholdId());
        if (household == null || YesOrNotEnum.Y.getCode().equals(household.getDelFlag())) {
            throw new BusinessException(HouseholdEnum.HOUSEHOLD_NOT_FOUND);
        }

        List<Long> memberIds = householdMemberService.listByHouseholdId(request.getHouseholdId()).stream().map(HouseholdMember::getMemberId).collect(Collectors.toList());
        List<Long> housingIds = housingInfoService.listByHouseholdId(request.getHouseholdId()).stream().map(HousingInfo::getHousingId).collect(Collectors.toList());

        List<HouseholdMember> members = new ArrayList<>();
        // 家庭成员临时ID与实际ID映射
        Map<Long, Long> memberTmpIdMap = new HashMap<>();
        for (HouseholdMemberRequest memberRequest: request.getMembers()) {
            ValidatorUtils.validate(memberRequest, BaseRequest.edit.class);

            HouseholdMember member = new HouseholdMember();
            BeanUtil.copyProperties(memberRequest, member);
            if (!memberIds.contains(memberRequest.getMemberId())) {
                member.setMemberId(IdUtil.getSnowflake().nextId());
            }
            member.setHouseholdId(household.getHouseholdId());

            members.add(member);
            memberTmpIdMap.put(memberRequest.getMemberId(), member.getMemberId());
        }

        List<HousingInfo> housingInfos = new ArrayList<>();
        Double householdArea = 0d;
        for (HousingInfoRequest housingInfoRequest: request.getHousingInfos()) {
            ValidatorUtils.validate(housingInfoRequest, BaseRequest.edit.class);

            HousingInfo housingInfo = new HousingInfo();
            BeanUtil.copyProperties(housingInfoRequest, housingInfo);
            housingInfo.setHouseholdId(household.getHouseholdId());
            housingInfo.setHousingOwnerId(memberTmpIdMap.get(housingInfoRequest.getHousingOwnerId()));

            housingInfos.add(housingInfo);
            householdArea += housingInfo.getHousingArea();
        }

        household.setHouseholdNo(request.getHouseholdNo());
        household.setHouseholdOwnerName(request.getHouseholdOwnerName());
        household.setHouseholdAddress(request.getHouseholdAddress());
        household.setHouseholdSize(members.size());
        household.setHouseholdArea(householdArea);
        householdMemberService.removeBatchByIds(memberIds);
        housingInfoService.removeBatchByIds(housingIds);
        this.updateById(household);
        householdMemberService.saveBatch(members);
        housingInfoService.saveBatch(housingInfos);
    }

    /**
     * 权属户详细信息
     * @param request 查询参数
     * @return HouseholdDto
     */
    @Override
    public HouseholdDto detail(HouseholdRequest request) {
        Household household = this.getById(request.getHouseholdId());
        if (household == null || YesOrNotEnum.Y.getCode().equals(household.getDelFlag())) {
            throw new BusinessException(HouseholdEnum.HOUSEHOLD_NOT_FOUND);
        }

        HouseholdDto householdDto = new HouseholdDto();
        BeanUtil.copyProperties(household, householdDto);

        List<HouseholdMember> members = householdMemberService.listByHouseholdId(household.getHouseholdId());
        List<HousingInfo> housingInfos = housingInfoService.listByHouseholdId(household.getHouseholdId());

        householdDto.setMembers(members);
        householdDto.setHousingInfos(housingInfos);

        return householdDto;
    }

    /**
     * 组建查询wrapper
     * @param request 查询参数
     * @return LambdaQueryWrapper
     */
    private LambdaQueryWrapper<Household> createWrapper(HouseholdRequest request) {
        LambdaQueryWrapper<Household> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(ObjectUtil.isNotEmpty(request.getHouseholdOwnerName()), Household::getHouseholdOwnerName, request.getHouseholdOwnerName());
        wrapper.ge(ObjectUtil.isNotNull(request.getHouseholdSizeFrom()), Household::getHouseholdSize, request.getHouseholdSizeFrom());
        wrapper.le(ObjectUtil.isNotNull(request.getHouseholdSizeTo()), Household::getHouseholdSize, request.getHouseholdSizeTo());
        wrapper.ge(ObjectUtil.isNotNull(request.getHouseholdAreaFrom()), Household::getHouseholdArea, request.getHouseholdAreaFrom());
        wrapper.le(ObjectUtil.isNotNull(request.getHouseholdAreaTo()), Household::getHouseholdArea, request.getHouseholdAreaTo());

        return wrapper;
    }

}
